﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace System.Threading.Tasks
{
    /// <summary>
    /// 表示异步锁，用于控制并发访问
    /// </summary>
    /// <creator>marc</creator>
    public class AsyncLock
    {
        /// <summary>
        /// 信号管理器<br/>请注意，此处应定为静态变量，防止被实例化
        /// </summary>
        private readonly static SemaphoreSlimManager _semaphoreSlimManager = new SemaphoreSlimManager();

        /// <inheritdoc cref="AsyncLock"/>
        public AsyncLock()
        {

        }

        /// <summary>
        /// 异步锁
        /// </summary>
        /// <param name="id">代表信号量的唯一ID。同一个ID的信号会等待上一次的结束，不一样的ID，则各自独立进行</param>
        /// <param name="cancellationToken">线程取消的令牌</param>
        /// <returns></returns>
        public async Task<IDisposable> LockAsync(string id, CancellationToken cancellationToken = default)
        {
            Check.NotNullOrEmpty(id, nameof(id));

            var semaphore = _semaphoreSlimManager.GetSemaphoreSlim(id);

            await semaphore.WaitAsync(cancellationToken);
            return new LockRelease(semaphore);
        }

        private class LockRelease : IDisposable
        {
            private readonly SemaphoreSlim _semaphore;
            private bool _isDisposed = false;

            /// <summary>
            /// 释放锁
            /// </summary>
            /// <param name="semaphore"></param>
            public LockRelease(SemaphoreSlim semaphore)
            {
                this._semaphore = semaphore;
            }

            /// <inheritdoc/>
            public void Dispose()
            {
                if (!_isDisposed)
                {
                    _semaphore.Release();
                    _isDisposed = true;
                }
            }
        }
    }

    /// <summary>
    /// 表示信号管理器
    /// <para>
    /// 用于管理每个规则对应的信号量，防止不同线程的同名信号相互冲突影响
    /// </para>
    /// </summary>
    public class SemaphoreSlimManager
    {
        private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();

        /// <inheritdoc cref="SemaphoreSlimManager"/>
        public SemaphoreSlimManager() { }

        /// <summary>
        /// 获取一个信号量
        /// </summary>
        /// <param name="id">规则</param>
        /// <returns>与指定规则对应的信号量</returns>
        public SemaphoreSlim GetSemaphoreSlim(string id)
        {
            Check.NotNullOrEmpty(id, nameof(id));

            // 使用 GetOrAdd 方法确保线程安全地获取或添加 SemaphoreSlim 实例
            return _semaphores.GetOrAdd(id, _ => new SemaphoreSlim(1, 1));
        }
    }
}
